'use strict';

const Service = require('egg').Service;

/*
 * type:
 * reply: xx 回复了你的话题
 * reply2: xx 在话题中回复了你
 * follow: xx 订阅了你
 * at: xx ＠了你
 */

class MessageSvc extends Service {
  /*
   * 根据用户ID，获取未读消息的数量
   * Callback:
   * @param {String} id 用户ID
   * @return {Promise[messagesCount]} 承载消息列表的 Promise 对象
   */
  getMessagesCount(id) {
    return this.ctx.model.Message.count({
      master_id: id,
      has_read: false,
    }).exec();
  }

  async getMessageRelations(message) {
    if (
      message.type === 'reply'
      || message.type === 'reply2'
      || message.type === 'at'
      || message.type === 'newTopic'
    ) {
      const [author, topic, reply] = await Promise.all([
        this.service.userSvc.getUserById(message.author_id),
        this.service.topicSvc.getTopicById(message.topic_id),
        this.service.replySvc.getReplyById(message.reply_id),
      ]);

      message.author = author;
      message.topic = topic;
      message.reply = reply;

      if (!author || !topic) {
        message.is_invalid = true;
      }
      return message;
    } else if (
      message.type == 'follow'
      || message.type == 'customize'
      || message.type == 'customizeSuccess'
      || message.type == 'customizeFailed'
    ) {
      message.author = await this.service.userSvc.getUserById(message.author_id);
      return message;
    }

    return {is_invalid: true};
  }

  /*
   * 根据消息Id获取消息
   * @param {String} id 消息ID
   * @return {Promise[message]} 承载消息的 Promise 对象
   */
  async getMessageById(id) {
    const message = await this.ctx.model.Message.findOne({_id: id}).exec();
    return this.getMessageRelations(message);
  }

  /*
   * 根据用户ID，获取已读消息列表
   * @param {String} userId 用户ID
   * @return {Promise[messages]} 承载消息列表的 Promise 对象
   */
  getReadMessagesByUserId(userId) {
    const query = {master_id: userId, has_read: true};
    return this.ctx.model.Message.find(query, null, {
      sort: '-createdAt',
      limit: 20,
    }).exec();
  }

  /*
   * 根据用户ID，获取未读消息列表
   * @param {String} userId 用户ID
   * @return {Promise[messages]} 承载消息列表的 Promise 对象
   */
  getUnreadMessagesByUserId(userId) {
    const query = {master_id: userId, has_read: false};
    return this.ctx.model.Message.find(query, null, {
      sort: '-createdAt',
    }).exec();
  }

  /*
   * 将消息设置成已读
   * @return {Promise[messages]} 承载消息列表的 Promise 对象
   */
  async updateMessagesToRead(userId, messages) {
    if (messages.length === 0) {
      return;
    }

    const ids = messages.map(function (m) {
      return m.id;
    });

    const query = {master_id: userId, _id: {$in: ids}};
    const update = {$set: {has_read: true}};
    const opts = {multi: true};
    return this.ctx.model.Message.update(query, update, opts).exec();
  }

  /**
   * 将单个消息设置成已读
   * @param {String} msgId 消息 ID
   * @return {Promise} 更新消息返回的 Promise 对象
   */
  async updateOneMessageToRead(msgId) {
    if (!msgId) {
      return;
    }
    const query = {_id: msgId};
    const update = {$set: {has_read: true}};
    return this.ctx.model.Message.update(query, update, {multi: true}).exec();
  }

  async _fillMoreMessageInfo(message) {
    const {ctx} = this;
    ctx.logger.warn('1:', message);

    const master_user = await ctx.model.User.findOne({_id: message.master_id}, {loginname: 1});
    message.master_name = master_user.loginname;
    const author_user = await ctx.model.User.findOne({_id: message.author_id}, {loginname: 1});
    message.author_name = author_user.loginname;

    if (message.topic_id) {
      const topic = await ctx.model.Topic.findOne({_id: message.topic_id}, {title: 1});
      message.topic_title = topic.title;
    }
  }

  async sendAtMessage(master_id, author_id, topic_id, reply_id) {
    const {ctx} = this;
    const message = ctx.model.Message();

    message.type = 'at';
    message.master_id = master_id;
    message.author_id = author_id;
    message.topic_id = topic_id;
    message.reply_id = reply_id;

    await this._fillMoreMessageInfo(message);
    return message.save();
  }

  async sendReplyMessage(userId, authorId, topicId, replyId) {
    const message = this.ctx.model.Message();

    message.type = 'reply';
    message.master_id = userId;
    message.author_id = authorId;
    message.topic_id = topicId;
    message.reply_id = replyId;

    await this._fillMoreMessageInfo(message);
    return message.save();
  }


  async sendReply2Message(userId, authorId, topicId, replyId) {
    const message = this.ctx.model.Message();

    message.type = 'reply2';
    message.master_id = userId;
    message.author_id = authorId;
    message.topic_id = topicId;
    message.reply_id = replyId;

    await this._fillMoreMessageInfo(message);
    return message.save();
  }


  async sendFollowMessage(superstar_id, fan_id) {
    const message = this.ctx.model.Message();

    message.type = 'follow';
    message.master_id = superstar_id;
    message.author_id = fan_id;

    await this._fillMoreMessageInfo(message);
    return message.save();
  }


  async sendCustomizeMessage(manager_id, user_id) {
    const message = this.ctx.model.Message();

    message.type = 'customize';
    message.master_id = manager_id;
    message.author_id = user_id;

    await this._fillMoreMessageInfo(message);
    return message.save();
  }


  async sendCustomizeSuccessMessage(superstar_id, fan_id) {
    const message = this.ctx.model.Message();

    message.type = 'customizeSuccess';
    message.master_id = fan_id;
    message.author_id = superstar_id;

    await this._fillMoreMessageInfo(message);
    return message.save();
  }


  async sendNewTopicMessage(manager_id, author_id, topic_id) {
    const message = this.ctx.model.Message();

    message.type = 'newTopic';
    message.master_id = manager_id;
    message.author_id = author_id;
    message.topic_id = topic_id;

    await this._fillMoreMessageInfo(message);
    return message.save();
  }
}

module.exports = MessageSvc;
